use leptos::prelude::*;
use leptos::task::spawn_local;
use leptos_router::hooks::{use_location, use_navigate};
use leptos_router::NavigateOptions;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use thaw::*;

use crate::components::atom::resize::PaneExpander;
use crate::components::user_profile::UserAvatarMenu;
use crate::pages::chat::Chat;
use crate::pages::email::*;

type NavPageFn = Box<dyn Fn() -> AnyView + Send + Sync>;

pub struct NavItem {
    pub path: &'static str,
    pub name: &'static str,
    pub icon: icondata::Icon,
    pub page: Option<NavPageFn>,
}

impl NavItem {
    pub fn items() -> Vec<NavItem> {
        vec![
            NavItem {
                path: "/home/chat",
                name: "消息",
                icon: icondata::BsChatFill,
                page: Some(Box::new(|| view! { <Chat /> }.into_any())),
            },
            NavItem {
                path: "/home/email",
                name: "邮件",
                icon: icondata::MdiEmail,
                page: Some(Box::new(|| view! { <Email /> }.into_any())),
            },
        ]
    }

    pub fn page_map(items: &mut Vec<NavItem>) -> HashMap<String, NavPageFn> {
        let mut map = HashMap::new();
        for item in items {
            if let Some(page) = item.page.take() {
                map.insert(item.path.to_string(), page);
            }
        }
        map
    }
}

#[component]
pub fn NavMenuViews(
    nav_items: Vec<NavItem>,
    selected: RwSignal<String>,
    expand: RwSignal<bool>,
    side_bar_width: Memo<i32>,
) -> impl IntoView {
    let menu_views = nav_items.into_iter().map(|nav_item| {
        let icon_style = Memo::new(move |_| {
            if selected.get().eq(nav_item.path) {
                "color: rgb(250, 250, 250);".to_string()
            } else {
                "color: rgb(240, 240, 240);".to_string()
            }
        });
        let name_style = Memo::new(move |_| {
            if selected.get().eq(nav_item.path) {
                "color: rgb(250, 250, 250); font-size: 14px".to_string()
            } else {
                "color: rgb(240, 240, 240); font-size: 14px".to_string()
            }
        });
        let box_class = Memo::new(move |_| {
            if selected.get().eq(nav_item.path) {
                "bg-[#4d89da] hover:bg-[#619dee] flex border-solid rounded border border-transparent justify-center items-center".to_string()
            } else {
                "hover:bg-[#619dee] flex border-solid rounded border border-transparent justify-center items-center".to_string()
            }
        });
        let style_width = Memo::new(move |_| {
            let width = side_bar_width.get() - 10;
            format!("{width}px")
        });
        view! {
            {move || {
                if expand.get() {
                    view! {
                        <Space
                            on:click=move |_| {
                                selected.set(nav_item.path.to_string());
                            }
                            style:height=move || "40px"
                            style:width=style_width
                            class=box_class
                            vertical=false
                            gap=SpaceGap::Medium
                        >
                            <Icon style=icon_style width="20px" height="20px" icon=nav_item.icon />
                            <div style=name_style>{nav_item.name}</div>
                        </Space>
                    }
                        .into_any()
                } else {
                    view! {
                        <Space
                            on:click=move |_| {
                                selected.set(nav_item.path.to_string());
                            }
                            style:height=move || "50px"
                            style:width=style_width
                            class=box_class
                            vertical=true
                            gap=SpaceGap::Size(0)
                        >
                            <Icon style=icon_style width="20px" height="20px" icon=nav_item.icon />
                            <div style=name_style>{nav_item.name}</div>
                        </Space>
                    }
                        .into_any()
                }
            }}
        }
    }).collect_view();
    view! {
        <nav>
            <Space vertical=true gap=SpaceGap::Large>
                {menu_views}
            </Space>
        </nav>
    }
}

#[component]
pub fn NavPageViews(
    page_map: Arc<HashMap<String, NavPageFn>>,
    pages_path: RwSignal<HashSet<String>>,
    selected: RwSignal<String>,
) -> impl IntoView {
    view! {
        <For
            each=move || pages_path.get()
            key=|item| item.clone()
            children=move |item| {
                let view = page_map.get(&item);
                let view = match view {
                    Some(view) => view(),
                    None => view! { {selected} }.into_any(),
                };
                let style = move || {
                    if selected.get().eq(&item) { "" } else { "display: none;" }
                };
                view! {
                    <div style=style class="flex-grow h-full w-full flex flex-col">
                        {view}
                    </div>
                }
            }
        />
    }
}

#[component]
pub fn Home() -> impl IntoView {
    let mut nav_items = NavItem::items();
    let page_map: HashMap<String, NavPageFn> = NavItem::page_map(&mut nav_items);
    let page_map = Arc::new(page_map);
    let pages_path: RwSignal<HashSet<String>> = RwSignal::new(HashSet::new());

    let default = nav_items
        .first()
        .map(|t| t.path.to_string())
        .unwrap_or_default();
    let selected = RwSignal::new(default.clone());
    let loaction = use_location();

    let navigate = use_navigate();
    let page_map_ = page_map.clone();
    spawn_local(async move {
        let current_path = loaction.pathname.get_untracked();
        if !page_map_.contains_key(&current_path) {
            navigate(&default, NavigateOptions::default());
        }
    });

    
    let navigate = use_navigate();
    _ = selected.watch(move |path| {
        let pathname = loaction.pathname.get_untracked();
        if &pathname == path {
            return;
        }
        navigate(path, NavigateOptions::default());
    });
    Effect::new(move |_| {
        let name = loaction.pathname.get();
        if pages_path.get().contains(&name) {
            return;
        }
        selected.set(name.clone());
        pages_path.update(|list| {
            list.insert(name);
        });
    });
    let expand = RwSignal::new(false);
    let side_bar_width: Memo<i32> = Memo::new(move |_| if expand.get() { 140 } else { 60 });

    view! {
        <div
            oncontextmenu="return false;"
            class="select-none h-screen w-screen flex flex-row"
            style:gap="0px"
        >
            <div class="-translate-x-[0px] w-[4px] bg-[#3975c6] h-full"></div>
            <div
                class="bg-[#3975c6] h-full flex flex-col"
                style:width=move || format!("{}px", side_bar_width.get())
            >
                <div data-tauri-drag-region class="title flex h-[25px]"></div>
                <Space class="items-center" vertical=true gap=SpaceGap::Size(30)>
                    <UserAvatarMenu expand />
                    <NavMenuViews expand nav_items selected side_bar_width />
                </Space>
            </div>
            <PaneExpander
                expand
                class="-translate-x-[0px] w-[4px] bg-[#3975c6] h-full cursor-ew-resize"
            />

            <NavPageViews page_map pages_path selected />
        </div>
    }
}
